import json

import matplotlib as mpl
from flask import request

from app.Controllers.BaseController import BaseController
from app.Package.entity.PCARequestBody import PCARequestBody

mpl.use('Agg')
import matplotlib.pyplot as plt

from app.Service.ChemometricsTutorialsServices.CommonService import readData, getImagePath, getWebImagePath, \
    getProjectInfo
from app.Package.pyChemometrics.ChemometricsPCA import ChemometricsPCA
from app.Package.pyChemometrics.ChemometricsScaler import ChemometricsScaler


# 需要进行PCA的通用部分，读取项目的信息和表单中的信息用于填入PCA类中
def unpackPCARequestBody(input_data):
    xfile = input_data.xfile
    yfile = input_data.yfile
    ppmfile = input_data.ppmfile
    ncomps = input_data.ncomps
    scaling_type = input_data.scaling_type
    thread_path = input_data.thread_path
    return xfile, yfile, ppmfile, ncomps, scaling_type, thread_path


# 根据构造PCA所必须的元素，构造ChemometricsPCA类
def getPCAModel(xfile, yfile, ppmfile, ncomps, scaling_type, outliers_index=None):
    x, y, ppm = readData(xfile, yfile, ppmfile, outliers_index)
    PCA_model = ChemometricsPCA(ncomps=ncomps, scaler=ChemometricsScaler(scale_power=scaling_type))
    PCA_model.fit(x)
    return PCA_model, x, y, ppm


# 进行PCA时都会进行的步骤进行了提取
def PCACommonProcess():
    userId, projectId, data, label, coordinate, savePath = getProjectInfo()
    formdata = request.data.decode('utf-8')
    formjson = json.loads(formdata)
    PCA = PCARequestBody(data, label, coordinate, savePath)
    PCA.set_data(formjson)
    return PCA


# 读取文件并画图，没啥用
def importDataAndPlot(input_data):
    xfile, yfile, ppmfile, ncomps, scaling_type, thread_path = unpackPCARequestBody(input_data)
    x, y, ppm = readData(xfile, yfile, ppmfile)

    plt.figure()
    plt.plot(ppm, x.T)
    plt.title("Raw data")
    plt.xlabel("$\delta_H$ in ppm")
    plt.ylabel("Intensity (a.u.)")
    plt.gca().invert_xaxis()

    imageFilename = "RawData"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath": webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)


# 根据表单输入的信息构造PCA模型后，进行ScorePlot操作，并返回生成的图片的url
def getPCAScorePlot(input_data):
    xfile, yfile, ppmfile, ncomps, scaling_type, thread_path = unpackPCARequestBody(input_data)
    PCA_model, x, y, ppm = getPCAModel(xfile, yfile, ppmfile, ncomps, scaling_type, input_data.outliers_index)
    if input_data.discrete_label is not None:
        discrete_color = y[:, input_data.discrete_label]
    else:
        discrete_color = None
    fig, ax = PCA_model.plot_scores(comps=input_data.score_plot_comps, plot_title=input_data.plot_title,
                                    color=discrete_color, discrete=input_data.discrete,
                                    label_outliers=input_data.label_outliers)
    imageFilename = "PCAScore"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath": webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)


# 根据表单输入的信息构造PCA模型后，进行ScreePlot操作，并返回生成的图片的url
def getPCAScreePlot(input_data):
    xfile, yfile, ppmfile, ncomps, scaling_type, thread_path = unpackPCARequestBody(input_data)
    PCA_model, x, y, ppm = getPCAModel(xfile, yfile, ppmfile, ncomps, scaling_type, input_data.outliers_index)
    fig, ax = PCA_model.scree_plot(x, total_comps=input_data.scree_total_comps)
    imageFilename = "PCAScree"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath": webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)


# 根据表单输入的信息构造PCA模型后，进行CVPlot操作，并返回生成的图片的url
def getPCACvPlot(input_data):
    xfile, yfile, ppmfile, ncomps, scaling_type, thread_path = unpackPCARequestBody(input_data)
    PCA_model, x, y, ppm = getPCAModel(xfile, yfile, ppmfile, ncomps, scaling_type, input_data.outliers_index)
    q2x, fig, ax = PCA_model.repeated_cv(x, total_comps=input_data.cv_total_comps, repeats=input_data.cv_repeats)
    imageFilename = "PCACv"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath": webImagePath, "q2x": q2x}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)


# 根据表单输入的信息构造PCA模型后，进行DmodxPlot操作，并返回生成的图片的url
def getPCADmodxPlot(input_data):
    xfile, yfile, ppmfile, ncomps, scaling_type, thread_path = unpackPCARequestBody(input_data)
    PCA_model, x, y, ppm = getPCAModel(xfile, yfile, ppmfile, ncomps, scaling_type, input_data.outliers_index)
    fig, ax = PCA_model.plot_dmodx(x, label_outliers=input_data.dmodex_label_outliers, alpha=input_data.dmodex_alpha)
    imageFilename = "PCAdmodx"
    imagePath, shortPath = getImagePath(thread_path, imageFilename)
    plt.savefig(imagePath, dpi=input_data.dpi, bbox_inches='tight')
    webImagePath = getWebImagePath(thread_path, shortPath)
    resultData = {"webImagePath": webImagePath}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)


# 根据表单输入的信息构造PCA模型后，找出样本中的离群点，并返回离群点，但是返回的是删除后的索引
# 仍需要修改
def getPCAOutlier(input_data):
    xfile, yfile, ppmfile, ncomps, scaling_type, thread_path = unpackPCARequestBody(input_data)
    PCA_model, x, y, ppm = getPCAModel(xfile, yfile, ppmfile, ncomps, scaling_type, input_data.outliers_index)
    outlier_idx = PCA_model.outlier(x, measure=input_data.outlier_measure, alpha=input_data.outlier_alpha)
    resultData = {"outlierIndex": outlier_idx.tolist()}
    return BaseController().successData(msg='成功获取分析结果', data=resultData)
